package pi.server.network;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Random;

import pi.server.storage.client.Player;

public class ClientNetwork extends Thread {
	private ServerNetwork server;
	private Socket socket;

	public Player player;

	private InputStream inputStream;
	private OutputStream outputStream;
	private InputStreamReader inputStreamReader;
	private OutputStreamWriter outputStreamWriter;
	private BufferedReader in;
	private BufferedWriter out;

	public ClientNetwork(ServerNetwork server, Socket socket, boolean isToAdd) {
		this.server = server;
		this.socket = socket;
		this.player = new Player();
		this.player.idOnServer = server.clientsIds;
		this.player.username = "Unregistred Client Connection";
		this.player.isConnected = true;

		try {
			inputStream = this.socket.getInputStream();
			outputStream = this.socket.getOutputStream();
			inputStreamReader = new InputStreamReader(inputStream);
			outputStreamWriter = new OutputStreamWriter(outputStream);
			in = new BufferedReader(inputStreamReader);
			out = new BufferedWriter(outputStreamWriter);
		} catch (IOException e) {
			e.printStackTrace();
			RemoveThisClient();
		}

		if (isToAdd == true) {
			server.clientList.add(this);
		}
	}

	@Override
	public void run() {
		try {
			while (player.isConnected) {
				ProcessClientProtocol();
			}
		} catch (Exception e) {
			e.printStackTrace();
			RemoveThisClient();
		}
	}

	private void ProcessClientProtocol() {
		try {
			String receivedData = in.readLine();

			String unknownMessage = "King Of Wars - Server Message: you sent to server a unknown command!";

			if (receivedData != null) {
				boolean isProtocolCommand = receivedData.startsWith("/");

				if (isProtocolCommand == true) {
					String commandString = receivedData.substring(1);
					String receivedDataList[] = commandString.split(" ");
					String commandStringResult = "";
					commandString = receivedDataList[0];

					if (receivedDataList.length == 1) {
						if (commandString.equalsIgnoreCase("exit")) {
							QuittingFromServer();
						} else if (commandString.equalsIgnoreCase("serverSize")) {
							SendServerSizeToAllClients();
						} else if (commandString
								.equalsIgnoreCase("serverMapType")) {
							SendGameMapTypeToAllClients();
						} else if (commandString.equalsIgnoreCase("enemyTurn")) {
							ReceiveRequestToSendEnemyTurn();
						} else if (commandString
								.equalsIgnoreCase("enemyIdData")) {
							ReceiveRequestToSendEnemyIdData();
						} else if (commandString
								.equalsIgnoreCase("enemyAllUnitsDataByTrn")) {
							ReceiveRequestToSendAllEnemyUnitsDataByTurn();
						} else if (commandString
								.equalsIgnoreCase("meAllUnitsDataByTrn")) {
							ReceiveRequestToSendAllMEUnitsDataByTurn();
						} else if (commandString
								.equalsIgnoreCase("enemyNameData")) {
							ReceiveRequestToSendEnemyNameData();
						} else if (commandString
								.equalsIgnoreCase("enemyUnitsData")) {
							ReceiveRequestToSendEnemyUnitsData();
						} else {
							SendDataToClient(unknownMessage);
						}
					} else if (receivedDataList.length == 2) {
						commandStringResult = receivedDataList[1];

						if (commandString.equalsIgnoreCase("name")) {
							RegisterClientOnServer(commandStringResult);
						} else if (commandString.equalsIgnoreCase("myUnits")) {
							RegisterMyUnits(commandStringResult);
						} else if (commandString.equalsIgnoreCase("myTurn")) {
							RegisterMyTurn(commandStringResult);
						} else if (commandString
								.equalsIgnoreCase("myUnitDataByTurn")) {
							RegisterMyUnitsDataByTurn(commandStringResult);
						} else if (commandString
								.equalsIgnoreCase("enemyUnitDataByTurn")) {
							RegisterEnemyUnitsDataByOnTurn(commandStringResult);
						} else {
							SendDataToClient(unknownMessage);
						}
					} else {
						SendDataToClient(unknownMessage);
					}
				} else {
					SendDataToClient(unknownMessage);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			RemoveThisClient();
		}
	}

	void ShowData() {
		player.ShowData();
	}

	private void ReceiveRequestToSendEnemyTurn() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				otherClient.SendDataToClient("#enemyTurn " + player.isMyTurn);
				return;
			}
		}
	}

	private void ReceiveRequestToSendEnemyUnitsData() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				otherClient.SendDataToClient("#enemyUnitsData "
						+ player.unit1.id + "u" + player.unit2.id + "u"
						+ player.unit3.id + "u" + player.unit4.id + "u"
						+ player.unit5.id);
				return;
			}
		}
	}

	private void ReceiveRequestToSendEnemyIdData() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				otherClient.SendDataToClient("#enemyDataId "
						+ player.idOnServer);
				return;
			}
		}
	}

	private void ReceiveRequestToSendAllEnemyUnitsDataByTurn() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				String command = "#enemyAllUnitsDataByTrn "
						+ player.RegisterMyUnitOnMyEndTurn(player.unit1) + "v"
						+ player.RegisterMyUnitOnMyEndTurn(player.unit2) + "v"
						+ player.RegisterMyUnitOnMyEndTurn(player.unit3) + "v"
						+ player.RegisterMyUnitOnMyEndTurn(player.unit4) + "v"
						+ player.RegisterMyUnitOnMyEndTurn(player.unit5);

				otherClient.SendDataToClient(command);
				return;
			}
		}
	}

	private void ReceiveRequestToSendAllMEUnitsDataByTurn() {
		String command = "#meAllUnitsDataByTrn "
				+ player.RegisterMyUnitOnMyEndTurn(player.unit1) + "v"
				+ player.RegisterMyUnitOnMyEndTurn(player.unit2) + "v"
				+ player.RegisterMyUnitOnMyEndTurn(player.unit3) + "v"
				+ player.RegisterMyUnitOnMyEndTurn(player.unit4) + "v"
				+ player.RegisterMyUnitOnMyEndTurn(player.unit5);

		SendDataToClient(command);
	}

	private void ReceiveRequestToSendEnemyNameData() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				otherClient.SendDataToClient("#enemyDataName "
						+ player.username);
				return;
			}
		}
	}

	// Request To Send Enemy Data

	// Send My Data
	private void SendMyIdOnServerToAllClients() {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork currentClient = server.clientList.get(i);
			if (currentClient == this) {
				currentClient.SendDataToClient("#idOnServer "
						+ player.idOnServer);
			} else if (currentClient != this) {
				currentClient.SendDataToClient("#enemyDataId "
						+ player.idOnServer);
			}
		}
	}

	// Send My Data

	// Send Server Data
	public void SendServerSizeToAllClients() {
		SendDataToAllClients("#serverSize " + server.clientList.size());
	}

	static int randomMapType = 0;

	public void SendGameMapTypeToAllClients() {
		if (server.clientList.size() == 2) {
			if (randomMapType == 0) {
				Random r = new Random();
				randomMapType = r.nextInt(4);
			}

			SendDataToAllClients("#serverMapType " + (randomMapType + 1));
		}
	}

	// Send Server Data

	// Send Functions
	private void SendDataToClient(String message) {
		try {
			out.write(message + "\n");
			out.flush();
			server.program.serverGUI.SetText("Client '" + player.username
					+ "' on server send '" + message + "' to client.");
		} catch (Exception e) {
			e.printStackTrace();
			RemoveThisClient();
		}
	}

	private void SendDataToAllClients(String message) {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork currentClient = server.clientList.get(i);
			currentClient.SendDataToClient(message);
		}
	}

	// Send Functions

	// Local Server Functions
	public void KickedByServer() {
		SendDataToClient("#serverKickMe true");
		RemoveThisClient();
		server.program.serverGUI.SetText("Client '" + player.username
				+ "' on server was kicked by server.");
	}

	private void QuittingFromServer() {
		SendDataToClient("#exit " + player.isConnected);
		RemoveThisClient();
		server.program.serverGUI.SetText("Client '" + player.username
				+ "' on server are quitting from server.");
	}

	private void RegisterClientOnServer(String name) {
		server.program.serverGUI.SetText("Client '" + player.username
				+ "' on server register name '" + name + "'.");
		player.username = name;
		SendMyIdOnServerToAllClients();
	}

	private void RegisterMyUnits(String dataReceived) {
		String unitsIds[] = dataReceived.split("u");
		int unitsLengh = unitsIds.length;

		int units[] = new int[unitsLengh];
		for (int i = 0; i < unitsLengh; i++) {
			units[i] = Integer.parseInt(unitsIds[i]);
		}

		player.unit1.id = units[0];
		player.unit2.id = units[1];
		player.unit3.id = units[2];
		player.unit4.id = units[3];
		player.unit5.id = units[4];

		server.program.serverGUI.SetText("Client '" + player.username
				+ "' on server register units '" + player.unit1.id + " "
				+ player.unit2.id + " " + player.unit3.id + " "
				+ player.unit4.id + " " + player.unit5.id + "'.");
	}

	private void RegisterMyUnitsDataByTurn(String dataReceived) {
		String units[] = dataReceived.split("v");
		for (int i = 0; i < units.length; i++) {
			String currentUnit[] = units[i].split("u");

			switch (i) {
			case 0:// unit1
				player.unit1.x = Integer.parseInt(currentUnit[0]);
				player.unit1.y = Integer.parseInt(currentUnit[1]);
				player.unit1.life = Integer.parseInt(currentUnit[2]);
				break;
			case 1:// unit2
				player.unit2.x = Integer.parseInt(currentUnit[0]);
				player.unit2.y = Integer.parseInt(currentUnit[1]);
				player.unit2.life = Integer.parseInt(currentUnit[2]);
				break;
			case 2:// unit3
				player.unit3.x = Integer.parseInt(currentUnit[0]);
				player.unit3.y = Integer.parseInt(currentUnit[1]);
				player.unit3.life = Integer.parseInt(currentUnit[2]);
				break;
			case 3:// unit4
				player.unit4.x = Integer.parseInt(currentUnit[0]);
				player.unit4.y = Integer.parseInt(currentUnit[1]);
				player.unit4.life = Integer.parseInt(currentUnit[2]);
				break;
			case 4:// unit5
				player.unit5.x = Integer.parseInt(currentUnit[0]);
				player.unit5.y = Integer.parseInt(currentUnit[1]);
				player.unit5.life = Integer.parseInt(currentUnit[2]);
				break;
			}
		}
	}

	private void RegisterEnemyUnitsDataByOnTurn(String dataReceived) {
		for (int i = 0; i < server.clientList.size(); i++) {
			ClientNetwork otherClient = server.clientList.get(i);
			if (otherClient != this) {
				String units[] = dataReceived.split("v");
				for (int j = 0; j < units.length; j++) {
					String currentUnit[] = units[j].split("u");

					//TODO checkarrrrrrr
					//X, Y nao usados...//checar se for usar..
					switch (j) {
					case 0:// unit1
//						otherClient.player.unit1.x = Integer.parseInt(currentUnit[0]);
//						otherClient.player.unit1.y = Integer.parseInt(currentUnit[1]);
						otherClient.player.unit1.life = Integer.parseInt(currentUnit[2]);
						break;
					case 1:// unit2
//						otherClient.player.unit2.x = Integer.parseInt(currentUnit[0]);
//						otherClient.player.unit2.y = Integer.parseInt(currentUnit[1]);
						otherClient.player.unit2.life = Integer.parseInt(currentUnit[2]);
						break;
					case 2:// unit3
//						otherClient.player.unit3.x = Integer.parseInt(currentUnit[0]);
//						otherClient.player.unit3.y = Integer.parseInt(currentUnit[1]);
						otherClient.player.unit3.life = Integer.parseInt(currentUnit[2]);
						break;
					case 3:// unit4
//						otherClient.player.unit4.x = Integer.parseInt(currentUnit[0]);
//						otherClient.player.unit4.y = Integer.parseInt(currentUnit[1]);
						otherClient.player.unit4.life = Integer.parseInt(currentUnit[2]);
						break;
					case 4:// unit5
//						otherClient.player.unit5.x = Integer.parseInt(currentUnit[0]);
//						otherClient.player.unit5.y = Integer.parseInt(currentUnit[1]);
						otherClient.player.unit5.life = Integer.parseInt(currentUnit[2]);
						break;
					}
				}
				
				return;
			}
		}
	}

	private void RegisterMyTurn(String myTurn) {
		boolean myTurnOnServer = Boolean.parseBoolean(myTurn);

		if (myTurnOnServer == true) {
			player.isMyTurn = true;
		} else {
			player.isMyTurn = false;
		}
		server.program.serverGUI.SetText("Client '" + player.username
				+ "' on server register turn '" + player.isMyTurn + "'.");

		SendMyTurn();
		ReceiveRequestToSendEnemyTurn();
	}

	private void SendMyTurn() {
		SendDataToClient("#myTurn " + player.isMyTurn);
	}

	private void RemoveThisClient() {
		player.isConnected = false;
		server.RemoveClientAndRefreshClientList(this);
	}
	// Local Server Functions
}